﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace TangoGames.Base
{

    public class Sky:DrawableGameComponent 
    {
        private static float OFFSET_CAMERA_BACK = 20.0f;
        private static float OFFSET_CAMERA_UP = 5.0f;
        private static float OFFSET_CAMERA_LEFT = 0.0f;
        private static float CELL_SIZE = 10.0f;

        BasicEffect basicEffect;
        BasicCamera camera;
        VertexPositionNormalTexture[] m_vertices;
        int[] m_indices;
        Texture2D texture;

        float radius;

        Matrix world;

        public Sky(Game game,BasicCamera camera):base(game)
        {
            //camera
            this.camera = camera;

            //Criar novo efeito básico e propriedades:
            basicEffect = new BasicEffect(game.GraphicsDevice);

            basicEffect.LightingEnabled = false;
            //basicEffect.EnableDefaultLighting();
            //basicEffect.FogEnabled = true;
            //basicEffect.FogStart = 300f;
            //basicEffect.FogEnd = 1000f;
            //basicEffect.FogColor = Color.Black.ToVector3();

            //ativando as cores
            //basicEffect.VertexColorEnabled = false ;

            world = Matrix.Identity;

            texture = Game.Content.Load<Texture2D>("Textures/Sky/sky_dome_night");

            radius = camera.FarPlane / 2;

            basicEffect.TextureEnabled = true;
            basicEffect.Texture = texture;

            CreateSky(32, 32);

            game.Components.Add(this);

        }


        public void CreateSky(int numTransverse, int numParallel)
        {

            int totalVertices = (numParallel * numTransverse) + 1;
            int totalTriangles = numParallel + ( numParallel * 2  * (numTransverse - 1) );
            m_indices = new int[totalTriangles * 3];
            m_vertices = new VertexPositionNormalTexture[totalVertices];

            //int startXposition = 0;
            //int startZposition = 0;
            //int startYposition = radius;

            //int cellXsize = radius / numTransverse;
            //int cellYsize = radius / numTransverse;

            //int worldXposition;
            //int worldYPosition;
            //int worldZPosition;
            //// Fill in the vertices

            float rad360 = (float) ( 2 * Math.PI);

            float rad90 = (float) ( Math.PI / 2);
           
            float angleZStep = rad360 / numParallel;

            float angleYStep = rad90 / numTransverse;

            float radiusStep = 1.0f / (numTransverse + 1);

            float angleY;
            float angleZ;

            //int linearStep = radius / numTransverse;

            ////center triangles

            int count = 0;

            float coordX;
            float coordY;
            float coordZ;

            //ponto zero
            m_vertices[count].Position = new Vector3(0, radius, 0);
            m_vertices[count].Normal = Vector3.Down;
            m_vertices[count].TextureCoordinate.X = 0.5f;
            m_vertices[count].TextureCoordinate.Y = 0.5f;
            count++;

            for (int trans = 1; trans < numTransverse; trans++)
            {

                angleY = rad90 - (angleYStep * trans);

                for (float paral = 0; paral < numParallel ; paral++)
                {
                    angleZ = (angleZStep * paral);
                    //Your position in 3d is given by two angles (+ radius, which in your case is constant)
                    //x = r * cos(s) * sin(t) =>z
                    //y = r * sin(s) * sin(t) =>X
                    //z = r * cos(t) =>y
                    // here, s is the angle around the z-axis(angleY), and t is the height angle, measured 'down' from the z-axis (angleZ).

                    coordX = (float)(radius * Math.Cos(angleY) * Math.Cos(angleZ));
                    coordY = (float)(radius * Math.Sin(angleY));
                    coordZ = (float)(radius * Math.Cos(angleY) * Math.Sin(angleZ));

                    m_vertices[count].Position = new Vector3(coordX, coordY, coordZ);
                    m_vertices[count].Normal = Vector3.Down;

                    Vector2 interpol = new Vector2((float)(Math.Cos(angleY) * Math.Cos(angleZ)), (float)(Math.Cos(angleY) * Math.Sin(angleZ)));
                    interpol.Normalize();
                    //divide por 0.5 e soma 0.5 para deslocar o eixo para interpolação
                    interpol *= 0.5f *  trans * radiusStep ;
                    interpol += new Vector2(0.5f, 0.5f);
                    m_vertices[count].TextureCoordinate = interpol;

                    //m_vertices[count].TextureCoordinate.X = (float)((Math.Cos(angleY) * Math.Cos(angleZ) * 0.5f) + 0.5f);
                    //m_vertices[count].TextureCoordinate.Y = (float)((Math.Cos(angleY) * Math.Sin(angleZ) * 0.5f) + 0.5f);
                    count++;

                }

            }

            //Primeiro anel paralelo
            for (float paral = 0; paral < numParallel; paral++)
            {

                angleZ = (angleZStep * paral);
                coordX = (float)(radius * Math.Cos(angleZ));
                coordY = 0;
                coordZ = (float)(radius * Math.Sin(angleZ));

                m_vertices[count].Position = new Vector3(coordX, coordY, coordZ);
                m_vertices[count].Normal = Vector3.Down;
                m_vertices[count].TextureCoordinate.X = (float)((Math.Cos(angleZ) * 0.5f) + 0.5f);
                m_vertices[count].TextureCoordinate.Y = (float)((Math.Sin(angleZ) * 0.5f) + 0.5f);
                count++;
            }


            CalcIndices(numTransverse, numParallel); 

            //CalcNormals();
        }




        private void CalcIndices(int numTransverse, int numParallel )
        {
            int index = 0;
            //primeiros triangulos
            for (int paral= 1;  paral < numParallel ; paral++ )
            {
                m_indices[index] = 0;
                m_indices[index + 1] = paral+1;
                m_indices[index + 2] = paral ;

                index += 3;

                if (paral == numParallel - 1)
                {
                    m_indices[index] = 0;
                    m_indices[index + 1] = 1;
                    m_indices[index + 2] = numParallel;
                    index += 3;
                }
            }

            //demais triangulos do domo triangulos
            int start;
            for (int trans = 1; trans < numTransverse; trans++)
            {
                start = ((trans-1) * numParallel);
                for (int paral = 1; paral < numParallel; paral++)
                {
                    m_indices[index] = start + paral;
                    m_indices[index + 1] = start + paral + numParallel + 1;
                    m_indices[index + 2] = start + paral + numParallel;

                    index += 3;

                    m_indices[index] = start + paral;
                    m_indices[index + 1] = start + paral + 1;
                    m_indices[index + 2] = start + paral + numParallel + 1;

                    index += 3;

                    if (paral == numParallel - 1)
                    {
                        m_indices[index] = start + paral + 1;
                        m_indices[index + 1] = start + numParallel + 1;
                        m_indices[index + 2] = start + numParallel * 2;
                        index += 3;

                        m_indices[index] = start + paral + 1;
                        m_indices[index + 1] = start + 1;
                        m_indices[index + 2] = start + numParallel + 1;
                        index += 3;

                    }
                }
            }
        }

        private void CalcNormals()
        {
            for (int i = 1; i < m_vertices.Length; i++)
                    m_vertices[i].Normal = new Vector3(0, 0, 0);
 
            for (int i = 1; i < m_indices.Length / 3; i++)
            {
                int index1 = m_indices[i * 3];
                int index2 = m_indices[i * 3 + 1];
                int index3 = m_indices[i * 3 + 2];
 
                Vector3 side1 = m_vertices[index1].Position - m_vertices[index3].Position;
                Vector3 side2 = m_vertices[index1].Position - m_vertices[index2].Position;
                Vector3 normal = Vector3.Cross(side1, side2);
 
                m_vertices[index1].Normal -= normal;
                m_vertices[index2].Normal -= normal;
                m_vertices[index3].Normal -= normal;                
            }

            for (int i = 0; i < m_vertices.Length; i++)
                m_vertices[i].Normal.Normalize();
        }


        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            Vector3 pos = camera.Position;
            pos.Y = 0;
            world = Matrix.CreateTranslation(pos); 
        }

        public override void Draw(GameTime gameTime)
        {
            // Game.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;

            DepthStencilState antdepthState = Game.GraphicsDevice.DepthStencilState;
            DepthStencilState depthState = new DepthStencilState();
            depthState.DepthBufferEnable = true; /* Enable the depth buffer */
            depthState.DepthBufferWriteEnable = true; /* When drawing to the screen, write to the depth buffer */


            basicEffect.View = camera.ViewMatrix;
            basicEffect.Projection = camera.ProjectionMatrix;

            basicEffect.World = world;

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
               pass.Apply();

               //desenhando as primitivas
               Game.GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, m_vertices,
                   0, m_vertices.Length, m_indices,  0, m_indices.Length / 3);


            }

            //restaura depstate
            GraphicsDevice.DepthStencilState = antdepthState;


        }
    }
}
